/*
    实现以下功能:
    定时任务管理:
        1. 获取所有任务和动作列表 : timer_task_get_config
        2. 创建一个定时任务 : timer_task_add
        3. 修改一个定时任务 : timer_task_change
        4. 删除一个定时任务 : timer_task_delete
    反馈:
        0: 执行失败
        1: 成功执行
        Incorrect/incomplete parameters: 参数不完整/类型错误
*/

#include "esp_log.h"
#include "api_map.h"
#include "timer_task.h"

// static const char *const TAG = "timer_task";

static uint8_t timer_task_get_from_json(void *data, timer_task_t *task)
{
    if (!data || !task)
        return 0;
    /**
        {
            "name": "xxxxx",
            "enable": 1,
            "type": 0,
            "time_type": 0,
            "weekdays": 0,
            "start": {
                "hour": 6,
                "minute": 30,
                "action": {
                    "name": "xxxxx",
                    "handle": 0,
                    "param": 1,
                }
            },
            "end": {
                "hour": 19,
                "minute": 0,
                "action": {
                    "name": "xxxxx",
                    "handle": 0,
                    "param": 0,
                }
            }
        }
    */
    static const char *const obj_keys[] = {
        "name",
        "enable",
        "type",
        "time_type",
        "start",
        "end",
        "weekdays",
    };
#define obj_keys_len sizeof(obj_keys) / sizeof(obj_keys[0])
    cJSON *obj_list[obj_keys_len] = {0};
    for (uint8_t i = 0; i < obj_keys_len; i++)
    {
        if (!cJSON_HasObjectItem(data, obj_keys[i]))
            return 1;
        obj_list[i] = cJSON_GetObjectItem(data, obj_keys[i]);
    }

    static const char *const time_item_keys[] = {
        "hour",
        "minute",
        "action",
    };
#define time_item_len sizeof(time_item_keys) / sizeof(time_item_keys[0])
    cJSON *time_item[2][time_item_len] = {0};
    for (uint8_t idx = 0; idx < 2; idx++)
    {
        for (uint8_t i = 0; i < time_item_len; i++)
        {
            if (!cJSON_HasObjectItem(obj_list[4 + idx], time_item_keys[i]))
                return 1;
            time_item[idx][i] = cJSON_GetObjectItem(obj_list[4 + idx], time_item_keys[i]);
        }
    }

    static const char *const action_item_keys[] = {
        "name",
        "handle",
        "param",
    };
#define action_item_keys_len sizeof(action_item_keys) / sizeof(action_item_keys[0])
    cJSON *action_item[2][action_item_keys_len] = {0};
    for (uint8_t idx = 0; idx < 2; idx++)
    {
        for (uint8_t i = 0; i < action_item_keys_len; i++)
        {
            if (!cJSON_HasObjectItem(time_item[idx][2], action_item_keys[i]))
                return 1;
            action_item[idx][i] = cJSON_GetObjectItem(time_item[idx][2], action_item_keys[i]);
        }
    }

    strncpy(task->name, cJSON_GetStringValue(obj_list[0]), sizeof(task->name));
    task->enabled = cJSON_GetNumberValue(obj_list[1]);
    task->type = cJSON_GetNumberValue(obj_list[2]);
    task->time_type = cJSON_GetNumberValue(obj_list[3]);
    task->weekdays = cJSON_GetNumberValue(obj_list[6]);
    task->start.hour = cJSON_GetNumberValue(time_item[0][0]);
    task->start.minute = cJSON_GetNumberValue(time_item[0][1]);
    task->end.hour = cJSON_GetNumberValue(time_item[1][0]);
    task->end.minute = cJSON_GetNumberValue(time_item[1][1]);

    {
        char *name = cJSON_GetStringValue(action_item[0][0]);
        uint8_t handle = cJSON_GetNumberValue(action_item[0][1]);
        uint8_t param = cJSON_GetNumberValue(action_item[0][2]);
        strncpy(task->start_action.name, name, sizeof(task->start_action.name));
        task->start_action.handle = handle;
        task->start_action.param = param;
    }

    {
        char *name = cJSON_GetStringValue(action_item[1][0]);
        uint8_t handle = cJSON_GetNumberValue(action_item[1][1]);
        uint8_t param = cJSON_GetNumberValue(action_item[1][2]);
        strncpy(task->end_action.name, name, sizeof(task->end_action.name));
        task->end_action.handle = handle;
        task->end_action.param = param;
    }
    return 0;
}

static void timer_task_get_config(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    char *str = (char *)server->data;
    uint16_t len = 0;
    len += sprintf(&str[len], "{");
    len += sprintf(&str[len], "\"api\":\"%s\",", "timer_task_get_config");
    len += sprintf(&str[len], "\"data\":{");
    len += sprintf(&str[len], "\"tasks\":");
    len += timers_to_json(&str[len], sizeof(server->data) - len);
    len += sprintf(&str[len], "\"actions\":");
    len += timer_actions_to_json(&str[len], sizeof(server->data) - len);
    len--;
    len += sprintf(&str[len], "}");
    len += sprintf(&str[len], "}");
    frame->payload = server->data;
    frame->len = len;
}

static void timer_task_change(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    /**
        [......]
    */
    if (!cJSON_IsArray(data))
        return ws_reply_data(server, frame, "timer_task_change", "Data type error");
        
    timer_remove_all();

    uint8_t len = cJSON_GetArraySize(data);
    for (uint8_t i = 0; i < len; i++)
    {
        cJSON *item = cJSON_GetArrayItem(data, i);
        timer_task_t task = {0};
        if (timer_task_get_from_json(item, &task))
            return ws_reply_data(server, frame, "timer_task_change", "Incorrect/incomplete parameters");
        timer_add(&task);
    }

    timer_save();

    return ws_reply_status(server, frame, "timer_task_change", 0);
}

void timer_task_api_init()
{
    ADD_API_ITEM(timer_task_get_config);
    ADD_API_ITEM(timer_task_change);
}